package com.logicfishsoftware.owlet.ext.sesame;


import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.openrdf.model.Resource;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.object.ObjectConnection;
import org.openrdf.result.Result;

import com.logicfishsoftware.owlet.app.Application;
import com.logicfishsoftware.owlet.app.ApplicationException;
import com.logicfishsoftware.owlet.app.Operator;
import com.logicfishsoftware.owlet.app.object.ObjectException;
import com.logicfishsoftware.owlet.app.object.ObjectService;
import com.logicfishsoftware.owlet.app.runtime.RuntimeApplication;
import com.logicfishsoftware.owlet.app.runtime.TransactionalRuntime;

/**
 * Hello world!
 *
 */ 
public final class AlibabaApplication 
extends TransactionalRuntime<AlibabaApplication.AlibabaAtom,AlibabaApplication.AlibabaContext>
implements Application<AlibabaApplication.AlibabaOperator>
{
	public interface AlibabaOperator 
	extends Operator<AlibabaContext> {
		/**
		 * @return
		 */
		ObjectConnection getConnection() throws ApplicationException;

		/**
		 * @param connection
		 * @throws RepositoryException 
		 */
		void dispose(ObjectConnection connection) throws ApplicationException;

		/**
		 * @param context
		 * @return
		 */
		boolean application(AlibabaContext context) throws Exception;
		
	}
	
    /**
	 * @author logicfish@gmail.com
	 *
	 */
	public abstract class AlibabaContext 
	extends TransactionalRuntime<AlibabaAtom,AlibabaContext>.TransactionalContext 
	implements ObjectService {
		private AlibabaContext() {
		}

		/**
		 * @return
		 */
		public abstract RepositoryConnection getConnection() throws ApplicationException;
	}

	/**
	 * @author logicfish@gmail.com
	 *
	 */
	protected final class AlibabaAtom extends RuntimeApplication<AlibabaAtom,AlibabaContext>.ApplicationAtom {
		private AlibabaOperator delegate;

		/**
		 * 
		 */
		private AlibabaAtom(AlibabaOperator delegate) {
			this.delegate = delegate;
		}
		/**
		 * @param tail
		 */
		public AlibabaAtom(Operator<? super AlibabaContext> tail) {
			this((AlibabaOperator)tail);
		}
		ObjectConnection getConnection() throws Exception {
			return delegate.getConnection();
		}
		/**
		 * @param connection
		 * @throws ApplicationException 
		 */
		public void dispose(ObjectConnection connection) throws ApplicationException {
			delegate.dispose(connection);
		}

		/* (non-Javadoc)
		 * @see com.logicfishsoftware.owlet.app.app.ApplicationRuntime.ApplicationAtom#application(com.logicfishsoftware.owlet.app.app.ApplicationRuntime.ApplicationFrame)
		 */
		@Override
		public boolean application(AlibabaContext context) throws Exception {
			return delegate.application(context);
		}

		/* (non-Javadoc)
		 * @see com.logicfishsoftware.owlet.app.app.ApplicationRuntime.ApplicationAtom#proceed()
		 */
		@Override
		public AlibabaAtom proceed() throws ApplicationException {
			Operator<AlibabaContext> tail = delegate.proceed();
			delegate = null;
			if(tail!=null)
				return new AlibabaAtom(tail);
			return null;
		}

	}

	/* (non-Javadoc)
	 * @see com.logicfishsoftware.owlet.app.app.ApplicationRuntime#createFrame(com.logicfishsoftware.owlet.app.app.ApplicationRuntime.ApplicationAtom)
	 */
	@Override
	protected AlibabaContext createAppContext(final AlibabaAtom atomic) {
		return new AlibabaContext() {
			public ObjectConnection getConnection() throws ObjectException {
				ObjectConnection connection;
				try {
					connection = atomic.getConnection();
				} catch (Exception e) {
					throw new ObjectException(e);
				}
				if(connection==null) throw new ObjectException("Alibaba is not connected.");
				return connection;
			}
						
			public void dispose() throws ApplicationException {
				ObjectConnection connection;
				try {
					connection = atomic.getConnection();
				} catch (Exception e) {
					throw new ObjectException(e);
				}
				if(connection==null) 
					return;				
				atomic.dispose(connection);
				connection=null;
			}
			
			@Override
			public void rollback(AlibabaAtom atom) throws ApplicationException {
				ObjectConnection connection = this.getConnection();
				try {
					connection.rollback();
				} catch (RepositoryException e) {
					throw new ObjectException(e);
				}
			}
			
			@Override
			public void commit(AlibabaAtom atom) throws ApplicationException {
				ObjectConnection connection = this.getConnection();
				try {
					connection.commit();
				} catch (RepositoryException e) {
					throw new ObjectException(e);
				}
			}
			
//			@Override
			public <K> void put(K obj, String iri)
					throws ObjectException {
				ObjectConnection connection = this.getConnection();
				try {
					connection.addObject(iri,obj);
				} catch (RepositoryException e) {
					throw new ObjectException(e);
				}
			}
			
//			@Override
			public <K> Set<K> getAll(Class<K> clazz) throws ObjectException {
				ObjectConnection connection = this.getConnection();
				try {
					Result<K> objects = connection.getObjects(clazz);
					return objects.asSet();
				} catch (RepositoryException e) {
					throw new ObjectException(e);
				} catch (QueryEvaluationException e) {
					throw new ObjectException(e);
				}
			}
			
//			@Override
			public <K> K get(String iri, Class<K> clazz) throws ObjectException {
				ObjectConnection connection = this.getConnection();
				try {
					return connection.getObject(clazz,iri);
				} catch (RepositoryException e) {
					throw new ObjectException(e);
				} catch (QueryEvaluationException e) {
					throw new ObjectException(e);
				}
			}

//			@Override
			public void clear(String ... iri) throws ObjectException {
				ObjectConnection connection = this.getConnection();
				try {
					if(iri.length == 0) {
						connection.clear();
						return;
					}
					List<Resource> uri = new ArrayList<Resource>();
					for (String _iri : iri) {
						uri.add(connection.getValueFactory().createURI(_iri));
					}
					connection.clear(uri.toArray(new Resource[uri.size()]));
				} catch (RepositoryException e) {
					throw new ObjectException(e);
				}
			}
		};
	}

	public boolean enter(AlibabaOperator atom) throws ApplicationException {
		return enter(createAtom(atom));
	}
		
	public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }

	/* (non-Javadoc)
	 * @see com.logicfishsoftware.owlet.app.runtime.RuntimeApplication#createAtom(com.logicfishsoftware.owlet.app.Operator)
	 */
	@Override
	protected AlibabaAtom createAtom(Operator<? super AlibabaContext> delegate)
			throws ApplicationException {
		return new AlibabaAtom(delegate);
	}

}
